package sg.edu.nus.iss.billing.controller;

import java.util.ArrayList;
import java.util.List;

import sg.edu.nus.iss.billing.constant.ErrorCodeConstants;
import sg.edu.nus.iss.billing.datastore.DBFactory;
import sg.edu.nus.iss.billing.datastore.IDataStore;
import sg.edu.nus.iss.billing.datastore.impl.Selector;
import sg.edu.nus.iss.billing.exception.ControllerException;
import sg.edu.nus.iss.billing.exception.DataStoreException;
import sg.edu.nus.iss.billing.localization.MessageKeyManager;
import sg.edu.nus.iss.billing.privilege.AdminRole;
import sg.edu.nus.iss.billing.privilege.AgentRole;
import sg.edu.nus.iss.billing.privilege.Role;
import sg.edu.nus.iss.billing.privilege.User;
import sg.edu.nus.iss.billing.util.Util;

public class UserController {

	private IDataStore dataStorage;

	public UserController() {
		dataStorage = DBFactory.instance().getSDStore();
	}

	public List<User> getAllUsers() throws ControllerException {
		List<User> userList = new ArrayList<User>();
		try {
			userList = dataStorage.loadObjectsByType(User.class);
		} catch (DataStoreException e) {
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		return userList;
	}
	
	public User findUser(String username) throws ControllerException {
		List<User> userList = null;
		User userObj = null;
		Selector selector = new Selector();
		selector.eq("username", username.toLowerCase());
		try {
			userList = dataStorage.loadObjectsBySelector(User.class, selector);
		} catch (DataStoreException e) {
			// e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (userList != null && userList.size() > 0) {
			userObj = userList.get(0);
		}
		return userObj;
	}

	public User getUserByName(String username) throws ControllerException {
		List<User> userList = null;
		User userObj = null;
		Selector selector = new Selector();
		selector.eq("username", username.toLowerCase());
		try {
			userList = dataStorage.loadObjectsBySelector(User.class, selector);
		} catch (DataStoreException e) {
			// e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (!Util.isEmpty(userList)) {
			userObj = userList.get(0);
		} else {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_CUSTOMER_NOT_FOUND,
					MessageKeyManager.getMessage("error.userNotFound"));
		}
		return userObj;
	}

	public User getUserByName(String username, boolean strict)
			throws ControllerException {
		User userObj = getUserByName(username);
		if (strict) {
			if (userObj == null) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_USER_NOT_FOUND,
						MessageKeyManager.getMessage("error.userNotFound"));
			}
			return userObj;
		} else {
			return userObj;
		}

	}

	public boolean authenticateUser(String username, String password)
			throws ControllerException {
		boolean authStatus = false;
		User userObj = getUserByName(username);
		if ((userObj.getPassword().equals(password))) {
			authStatus = true;
		} else {
		  throw new ControllerException(
          ErrorCodeConstants.ERROR_USER_AUTHENTICATION_FAILED,
          MessageKeyManager.getMessage("error.authenticationFailed"));
		}
		return authStatus;
	}

	public boolean validateUserID(User userObj) throws ControllerException {
		String custID = userObj.getId();
		if (Util.isEmpty(custID)) {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_USER_NOT_FOUND,
					MessageKeyManager.getMessage("error.userNotFound"));
		} else {
			return true;
		}
	}

	public void addUser(String username, String password, Role role)
			throws ControllerException {
		Role roleObj = null;
		User userObj = null;
		password = password.trim();
		
		// check if username is exist
        userObj = findUser(username);
        if (userObj != null) {
            throw new ControllerException(
                    ErrorCodeConstants.ERROR_USER_DUPLICATION,
                    MessageKeyManager.getMessage("error.userDuplication"));
        }

        // check if password is entered
        if (password == null && "".equals(password)) {
            throw new ControllerException(
                    ErrorCodeConstants.ERROR_ENTRY_NO_PASSWORD,
                    MessageKeyManager.getMessage("error.userNoPassword"));
        }

        // check if role is selected
        if (role != null && !"".equals(role)) {
            if (role instanceof AdminRole) {
                roleObj = (AdminRole) role;
            }
            if (role instanceof AgentRole) {
                roleObj = (AgentRole) role;
            }
        } else {
            throw new ControllerException(
                    ErrorCodeConstants.ERROR_ENTRY_ROLE_EMPTY,
                    MessageKeyManager.getMessage("error.userRoleEmpty"));
        }
        
		try {
			// store user
			userObj = new User(username.toLowerCase(), password, roleObj);
			dataStorage.saveObject(userObj);
		} catch (DataStoreException e) {
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
	}

	public void removeUser(User userObj) throws ControllerException {
		if (validateUserID(userObj)) {
			try {
				dataStorage.deleteObjectByID(User.class, userObj.getId());
			} catch (DataStoreException e) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_DATASTORE,
						MessageKeyManager.getMessage("error.dataStore"));
			}
		}
	}
	
	public void removeUserList(List<String> usernameList) throws ControllerException {
		if (usernameList == null || usernameList.size() == 0) {
			throw new ControllerException(ErrorCodeConstants.ERROR_USER_SELECTED, MessageKeyManager.getMessage("error.userSelect", "delete operation"));
		}
		for (int i=0; i < usernameList.size(); i++) {
			User userObj = getUserByName(usernameList.get(i));
			removeUser(userObj);
		}
	}

	public void editUser(User userObj) throws ControllerException {
		if (validateUserID(userObj)) {
			try {
				dataStorage.saveObject(userObj);
			} catch (DataStoreException e) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_DATASTORE,
						MessageKeyManager.getMessage("error.dataStore"));
			}
		}
	}

	public void changePassword(String username, String oldPassword,
			String newPassword) throws ControllerException {
		User userObj = null;
		userObj = getUserByName(username, true);
		newPassword = newPassword.trim();
		try {
			if (authenticateUser(username, oldPassword)) {
				userObj.setPassword(newPassword);
				dataStorage.saveObject(userObj);
			}
		} catch (DataStoreException e) {
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
	}
}
